package com.apex.lottery.service.impl;

import com.apex.lottery.common.errorcode.ServiceErrorCodeConstants;
import com.apex.lottery.common.utils.JacksonUtil;
import com.apex.lottery.common.utils.RedisUtil;
import com.apex.lottery.controller.param.DrawPrizeParam;
import com.apex.lottery.controller.param.ShowWinningRecordsParam;
import com.apex.lottery.dao.dataobject.*;
import com.apex.lottery.dao.mapper.*;
import com.apex.lottery.service.DrawPrizeService;
import com.apex.lottery.service.dto.ConvertActivityStatusDTO;
import com.apex.lottery.service.dto.WinningRecordDTO;
import com.apex.lottery.service.enums.ActivityPrizeStatusEnum;
import com.apex.lottery.service.enums.ActivityPrizeTiersEnum;
import com.apex.lottery.service.enums.ActivityStatusEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

import static com.apex.lottery.common.constant.Constants.*;

/**
 * @ClassName DrawPrizeServiceImpl
 * @Description
 * @Author ZJX
 * @Date 2025/4/20 19:07
 * @Version 1.0
 **/
@Service
public class DrawPrizeServiceImpl implements DrawPrizeService {
    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ActivityMapper activityMapper;

    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private AwardMapper prizeMapper;

    @Autowired
    private WinningRecordMapper winningRecordMapper;

    private static final Logger logger = LoggerFactory.getLogger(DrawPrizeServiceImpl.class);

    @Override
    public void drawPrize(DrawPrizeParam param) {
        Map<String, String> map = new HashMap<>();
        map.put("messageId", String.valueOf(UUID.randomUUID()));
        map.put("messageData", JacksonUtil.writeValueAsString(param));

        // 发消息: 交换机、绑定的key、消息体
        rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING, map);
        logger.info("mq消息发送成功：map={}", JacksonUtil.writeValueAsString(map));
    }

    @Override
    public Boolean checkDrawPrizeParam(DrawPrizeParam param) {
//        活动是否存在
        ActivityDO activityDO = activityMapper.selectById(param.getActivityId());
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());
        if (null == activityDO || null == activityPrizeDO){
//            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_IS_EMPTY);
            logger.info("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_IS_EMPTY.getMessage());
            return false;
        }
//        活动是否有效
        if (!activityDO.getStatus().equalsIgnoreCase(ActivityStatusEnum.RUNNING.name())){
            logger.info("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.ACTIVITY_COMPLETED.getMessage());
            return false;
        }

//        奖品是否有效
        if (activityPrizeDO.getStatus().equalsIgnoreCase(ActivityPrizeStatusEnum.COMPLETED.toString())){
            logger.info("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED.getMessage());
            return false;
        }

//        中奖者人数是否跟设置奖品数量一致
        if (param.getWinnerList().size() != activityPrizeDO.getPrizeAmount()){
            logger.info("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.WINNER_PRIZE_AMOUNT_ERROR.getMessage());
            return false;
        }
        return true;
    }

    @Override
    public List<WinningRecordDO> saveWinnerRecords(DrawPrizeParam param) {
//        查询相关信息 活动 人员 奖品
        ActivityDO activityDO = activityMapper.selectById(param.getActivityId());
        List<UserDO> userDOList = userMapper.batchSelectByIds(param.getWinnerList().stream()
                .map(DrawPrizeParam.Winner::getUserId).toList());

        AwardDO prizeDO = prizeMapper.selectById(param.getPrizeId());
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());

//        构造返回信息结构
        List<WinningRecordDO> winningRecordDOList = userDOList.stream()
                .map(userDO -> {
                    WinningRecordDO winningRecordDO = new WinningRecordDO();
                    winningRecordDO.setActivityId(activityDO.getId());
                    winningRecordDO.setActivityName(activityDO.getActivityName());
                    winningRecordDO.setPrizeId(prizeDO.getId());
                    winningRecordDO.setPrizeName(prizeDO.getName());
                    winningRecordDO.setPrizeTier(activityPrizeDO.getPrizeTiers());
                    winningRecordDO.setWinnerId(userDO.getId());
                    winningRecordDO.setWinnerName(userDO.getUserName());
                    winningRecordDO.setWinnerEmail(userDO.getEmail());
                    winningRecordDO.setWinnerPhoneNumber(userDO.getPhoneNumber());
                    winningRecordDO.setWinningTime(param.getWinningTime());
                    return winningRecordDO;
                }).toList();

//        缓存中奖者记录
        winningRecordMapper.batchInsert(winningRecordDOList);

        // 缓存中奖者记录
        // 1、缓存奖品维度中奖记录(WinningRecord_activityId_prizeId, winningRecordDOList（奖品维度的中奖名单）
        cacheWinningRecords(param.getActivityId() + "_" + param.getPrizeId(),
                winningRecordDOList,
                WINNING_RECORDS_TIMEOUT);


        // 2、缓存活动维度中奖记录(WinningRecord_activityId, winningRecordDOList(活动维度的中奖名单))
        // 当活动已完成再去存放活动维度中奖记录
        if (activityDO.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())){
            // 查询活动的全量中奖记录
            List<WinningRecordDO> prizeList = winningRecordMapper.selectByActivityId(param.getActivityId());
            cacheWinningRecords(String.valueOf(param.getActivityId()),prizeList,WINNING_RECORDS_TIMEOUT);
        }

        return winningRecordDOList;
    }

    @Override
    public void deleteRecords(Long activityId, Long prizeId) {
        if(activityId == null){
            logger.warn("要删除中奖记录相关的活动id为空！");
            return;
        }
//        删除数据表
        winningRecordMapper.deleteRecords(activityId,prizeId);

        if (null != prizeId) {
            deleteCacheWinningRecords(activityId + "_" + prizeId);
        }

//        删除缓存
        deleteCacheWinningRecords(String.valueOf(activityId));
    }

    @Override
    public List<WinningRecordDTO> getRecords(ShowWinningRecordsParam param) {
//        查询redis
        String key = null == param.getPrizeId()
                ? String.valueOf(param.getActivityId())   // 如果 PrizeId 为 null，则用 ActivityId 创建字符串
                : param.getActivityId() + "_" + param.getPrizeId();  // 如果 PrizeId 不为 null，则返回 ActivityId + "_" + PrizeId
        List<WinningRecordDO> winningRecordDOList = getCacheWinningRecords(key);
        if (!CollectionUtils.isEmpty(winningRecordDOList)){
            return convertToWinningRecordDTOList(winningRecordDOList);
        }

        // 如果redis不存在，查库
        winningRecordDOList = winningRecordMapper.selectByActivityIdOrPrizeId(
                param.getActivityId(), param.getPrizeId());
        // 存放记录到redis
        if (CollectionUtils.isEmpty(winningRecordDOList)) {
            logger.info("查询的中奖记录为空！param:{}",
                    JacksonUtil.writeValueAsString(param));
            return Arrays.asList();
        }
        cacheWinningRecords(key, winningRecordDOList, WINNING_RECORDS_TIMEOUT);
        return convertToWinningRecordDTOList(winningRecordDOList);
    }

    private List<WinningRecordDTO> convertToWinningRecordDTOList(List<WinningRecordDO> winningRecordDOList) {
        if (CollectionUtils.isEmpty(winningRecordDOList)){
            return List.of();
        }
        return winningRecordDOList.stream()
                .map(winningRecordDO -> {
                    WinningRecordDTO dto = new WinningRecordDTO();
                    dto.setPrizeName(winningRecordDO.getPrizeName());
                    dto.setPrizeTier(ActivityPrizeTiersEnum.forName(winningRecordDO.getPrizeTier()));
                    dto.setWinnerId(winningRecordDO.getWinnerId());
                    dto.setWinningTime(winningRecordDO.getWinningTime());
                    dto.setWinnerName(winningRecordDO.getWinnerName());
                    return dto;
                }).toList();
    }

    /**
     * 删除缓存中奖记录
     * @param key
     */
    private void deleteCacheWinningRecords(String key) {
        try {
            String winningRecordsKey = WINNING_RECORDS_PREFIX + key;
            if (redisUtil.hasKey(winningRecordsKey)) {
                redisUtil.del(winningRecordsKey);
            }
        } catch (Exception e) {
            logger.error("删除中奖记录缓存异常，key:{}", key);
        }

    }



    /**
     *  缓存中奖记录
     * @param key
     * @param winningRecordDOList
     * @param time
     */
    private void cacheWinningRecords(String key, List<WinningRecordDO> winningRecordDOList, Long time) {
        String str = "";
        try {
            if (!StringUtils.hasText(key) || CollectionUtils.isEmpty(winningRecordDOList)) {
                logger.warn("要缓存的内容为空！key:{}, value:{}",
                        key, JacksonUtil.writeValueAsString(winningRecordDOList));
                return;
            }

            str = JacksonUtil.writeValueAsString(winningRecordDOList);
            redisUtil.set(WINNING_RECORDS_PREFIX + key,
                    str,
                    time);
        } catch (Exception e) {
            logger.error("缓存中奖记录异常！key:{}, value:{}", WINNING_RECORDS_PREFIX + key, str);
        }
    }

    /**
     * 从缓存中获取中奖记录
     *
     * @param key
     * @return
     */
    private List<WinningRecordDO> getCacheWinningRecords(String key) {
        try {
            if (!StringUtils.hasText(key)){
                logger.warn("要从缓存中查询中奖记录的key为空！");
                return List.of();
            }

            String s = redisUtil.get(WINNING_RECORDS_PREFIX + key);
            if (!StringUtils.hasText(s)){
                return List.of();
            }
            return JacksonUtil.readListValue(s,WinningRecordDO.class);
        } catch (Exception e){
            logger.error("从缓存中查询中奖记录异常！key:{}", WINNING_RECORDS_PREFIX + key);
            return List.of();
        }
    }
}
